package chen.web.forum;

import java.util.List;

import chen.web.cache.Lockable;
import chen.web.cache.LockedException;
import chen.web.user.Account;
import chen.web.widget.Widget;

public class SubjectCondition implements Lockable{

	public static enum OrderBy {
		LastReplyDate {
			String getSQL() {
				return "sub_lastReplyDate";
			}
		},
		PublishDate {
			String getSQL() {
				return "sub_dateline";
			}
		};

		abstract String getSQL();
	}
	
	public static enum Order{
		Asc, Desc
	}
	
	/**
	 *主题的类型
	 */
	public static enum SubjectType{
		top, good, not_top
	}
	
	public SubjectCondition(){}
	
	private Category category;
	private boolean containsChildren = false;
	private SubjectType type = null;
	private Class<? extends Widget> widgetClass;
	private OrderBy orderBy = null;
	private Order order = null;
	private Account account;
	private boolean fakeDelete;
	private boolean needChecking;
	
	public Category getCategory() {
		return category;
	}
	public SubjectCondition setCategory(Category category) {
		if(lock) throw new LockedException();
		this.category = category;
		return this;
	}
	public boolean isContainsChildren() {
		return containsChildren;
	}
	public SubjectCondition setContainsChildren(boolean containsChildren) {
		if(lock) throw new LockedException();
		this.containsChildren = containsChildren;
		return this;
	}
	public Class<? extends Widget> getWidgetClass() {
		return widgetClass;
	}
	public SubjectCondition setWidgetClass(Class<? extends Widget> widgetClass) {
		if(lock) throw new LockedException();
		this.widgetClass = widgetClass;
		return this;
	}
	public Order getOrder() {
		return order;
	}
	public SubjectCondition setOrder(Order order) {
		if(lock) throw new LockedException();
		this.order = order;
		return this;
	}
	public SubjectCondition setType(SubjectType type) {
		if(lock) throw new LockedException();
		this.type = type;
		return this;
	}
	public SubjectType getType() {
		return type;
	}
	public SubjectCondition setOrderBy(OrderBy orderBy) {
		if(lock) throw new LockedException();
		this.orderBy = orderBy;
		return this;
	}
	public OrderBy getOrderBy() {
		return orderBy;
	}
	public SubjectCondition setAccount(Account account) {
		if(lock) throw new LockedException();
		this.account = account;
		return this;
	}
	public Account getAccount() {
		return account;
	}
	public SubjectCondition setFakeDelete(boolean fakeDelete) {
		if(lock) throw new LockedException();
		this.fakeDelete = fakeDelete;
		return this;
	}
	public boolean isFakeDelete() {
		return fakeDelete;
	}
	public SubjectCondition setNeedChecking(boolean needChecking) {
		if(lock) throw new LockedException();
		this.needChecking = needChecking;
		return this;
	}
	public boolean isNeedChecking() {
		return needChecking;
	}
	
	public String toSql(){
		String and = " and ";
		StringBuffer sql = new StringBuffer();
		
		if(getAccount() != null){
			sql.append("sub_authorId = ").append(getAccount().getId()).append(' ');
			sql.append(and);
		}
		if(getType() != null){
			switch(getType()){
			case not_top :
				sql.append("sub_top = 0 ");
				break;
			case top :
				sql.append("sub_top = 1 ");
				break;
			case good:
				sql.append("sub_good = 1 ");
				break;
			default : 
				throw new IllegalArgumentException();
			}	
			sql.append(and);
		}
		if(isNeedChecking()){ 		//需要审核的
			sql.append("sub_invisible = 2 ").append(and);
		} else if(isFakeDelete()){	//假删除的
			sql.append("sub_invisible = 1 ").append(and);
		} else {					//可见的
			sql.append("sub_invisible = 0 ").append(and);
		}
		if(getWidgetClass() != null){
			sql.append("sub_widgetType = ").append(WidgetType.getType(getWidgetClass())).append(' ');
			sql.append(and);
		}
		if(getCategory() != null && getCategory().getId() != CategoryManager.RootCategoryId){
			String cids = getCategoryIdStr(getCategory(), isContainsChildren());
			if(cids.length() != 0){
				sql.append("cat_id in(");
				sql.append(cids);
				sql.append(")");
				sql.append(and);	
			}
		}
		
		if(sql.length() > 0){
			sql.delete(sql.length()-and.length(), sql.length());	
			sql.insert(0, " where ");
		}
		
		if(getOrderBy() != null){
			sql.append(" order by ")
				.append(getOrderBy().getSQL()).append(" ")
				.append(getOrder().name()).append(" ");
		}
		return sql.toString();
	}
	
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return toSql();
	}
	
	static String getCategoryIdStr(Category category, boolean containsChildren){
		StringBuffer replacement = new StringBuffer();
		_getCategoryIdStr(category, containsChildren, replacement);
		if(replacement.length() > 0){
			replacement.deleteCharAt(replacement.length()-1);
		}
		return replacement.toString();
	}
	
	
	private static void _getCategoryIdStr(Category category, boolean containsChildren, StringBuffer sb){
		List<Category> children = category.getChildren();
		if(children.size() == 0){
			sb.append(category.getId());
			sb.append(",");
		}else {
			if(containsChildren){
				for(Category child : children){
					_getCategoryIdStr(child, containsChildren, sb);
				}
			}
		}
	}
	
	private boolean lock;
	@Override
	public void lock() {
		// TODO Auto-generated method stub
		lock = true;
	}
	@Override
	public void unlock() {
		// TODO Auto-generated method stub
		lock = false;
	}
	
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((account == null) ? 0 : account.hashCode());
		result = prime * result
				+ ((category == null) ? 0 : category.hashCode());
		result = prime * result + (containsChildren ? 1231 : 1237);
		result = prime * result + (lock ? 1231 : 1237);
		result = prime * result + ((order == null) ? 0 : order.hashCode());
		result = prime * result + ((orderBy == null) ? 0 : orderBy.hashCode());
		result = prime * result + ((type == null) ? 0 : type.hashCode());
		result = prime * result
				+ ((widgetClass == null) ? 0 : widgetClass.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		SubjectCondition other = (SubjectCondition) obj;
		if (account == null) {
			if (other.account != null)
				return false;
		} else if (!account.equals(other.account))
			return false;
		if (category == null) {
			if (other.category != null)
				return false;
		} else if (!category.equals(other.category))
			return false;
		if (containsChildren != other.containsChildren)
			return false;
		if (lock != other.lock)
			return false;
		if (order == null) {
			if (other.order != null)
				return false;
		} else if (!order.equals(other.order))
			return false;
		if (orderBy == null) {
			if (other.orderBy != null)
				return false;
		} else if (!orderBy.equals(other.orderBy))
			return false;
		if (type == null) {
			if (other.type != null)
				return false;
		} else if (!type.equals(other.type))
			return false;
		if (widgetClass == null) {
			if (other.widgetClass != null)
				return false;
		} else if (!widgetClass.equals(other.widgetClass))
			return false;
		return true;
	}
	
	
	
}
